package app;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

public class Collection {

	private HashSet<Car> allCars;
	private TreeSet<Destination> allDestination;
	private ArrayList<Journey> allJourney2015;
	private HashSet<Destination> allDestination2014;
	private HashSet<Destination> allDestination2015;
	private HashMap<Car, HashSet<Destination>> carAndDestination;
	private String report1;
	private String report2;
	private String report3;

	public Collection() {
		allCars = new HashSet<Car>();
		allDestination = new TreeSet<Destination>();
		allJourney2015 = new ArrayList<Journey>();
		allDestination2014 = new HashSet<Destination>();
		allDestination2015 = new HashSet<Destination>();
		carAndDestination = new HashMap<Car, HashSet<Destination>>();

	}

	/**sort the journey in 2015 by journey fee**/
	public void listByFee() {
		Collections.sort(allJourney2015, new JourneyFeeComparator());

	}
	/**read input files**/
	public void readFile(String file) throws IOException {

		String fileName;
		fileName = file;
		try {
			File inputFile = new File(fileName);
			Scanner line = new Scanner(inputFile);
			while (line.hasNextLine()) {
				String inputLine = line.nextLine();
				if (inputLine.length() != 0 && fileName == "taxi.txt") {
					processLineOfCar(inputLine);
				} else if (inputLine.length() != 0
						&& fileName == "destination.txt") {
					processLineOfDestination(inputLine);
				} else if (inputLine.length() != 0
						&& fileName == "journeys2015.txt") {
					processLineOfJourney(inputLine);
				} else if (inputLine.length() != 0
						&& fileName == "journeys2014.txt") {
					processLineOfJourney1(inputLine);
				}
			}
			line.close();
		} catch (FileNotFoundException fnf) {
			System.out.println("File not found ");
			System.exit(0);
		}
	} // end of READFILE

	/**
	 * get records from car text file and remove "," before loaded into set
	 * for processing
	 * 
	 * @param line
	 */
	private void processLineOfCar(String line) {

		try {
			String parts[] = line.split(",");
			String registrationNumber = parts[0];
			Name driverName = new Name(parts[1]);

			Car newCar = new Car(registrationNumber, driverName);
			allCars.add(newCar);
		} catch (NumberFormatException nfe) {
			String error = "Number conversion error in " + line + " "
					+ nfe.getMessage();
			System.out.println(error);
		} catch (ArrayIndexOutOfBoundsException air) {
			String error = "Not enought items in: " + line
					+ " index position: " + air.getMessage();
			System.out.println(error);
		} catch (RegistrationFormatException rfe) {
			String message = rfe.getMessage();
			System.out.println( "CAR " + message);
		} catch (DriverNameException dne) {
			String message1 = dne.getMessage();
			System.out.println("Driver name in CAR " + line + "WRONG." + message1);
		} catch (IllegalStateException ise) {
			String message2 = ise.getMessage();
			System.out.println(message2);
		} catch (Exception e) {
			e.printStackTrace();
		}
	} // end of PROCESSLINE OF CAR

	/**
	 * get records from destination text file and remove "," before loaded into
	 * set for processing
	 * 
	 * @param line
	 */
	private void processLineOfDestination(String line) {

		try {
			String parts[] = line.split(",");
			String destination = parts[0];
			double distance = Double.parseDouble(parts[1]);

			Destination newDestination = new Destination(destination, distance);
			allDestination.add(newDestination);
		} catch (NumberFormatException nfe) {
			String error = "Number conversion error in " + line + " "
					+ nfe.getMessage();
			System.out.println(error);
		} catch (ArrayIndexOutOfBoundsException air) {
			String error = "Not enought items in: " + line
					+ " index position: " + air.getMessage();
			System.out.println(error);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	} // end of PROCESSLINE OF Destination

	/**
	 * get records from 2015 journey text file and remove "," before loaded into
	 * array list for processing
	 * 
	 * @param line
	 */
	private void processLineOfJourney(String line) {

		try {
			Car taxi = null;
			Destination destination = null;
			String parts[] = line.split(",");
			String registrationNumber = parts[0];
			String location = parts[1];
			int seats = Integer.parseInt(parts[2]);
			int year = Integer.parseInt(parts[3]);

			for (Car car : allCars) {
				if (registrationNumber.equals(car.getRegistrationNumber())) {
					taxi = car;
				}
			}

			for (Destination place : allDestination) {
				if (location.equals(place.getDestination())) {
					destination = place;
				}
			}
			allDestination2015.add(destination);
			Journey newTrip = new Journey(taxi, destination, seats, year);
			allJourney2015.add(newTrip);
			if (taxi == null)
				return;
			// Get the set of destination for this car
			HashSet<Destination> de = carAndDestination.get(taxi);
			// If none so far, make new set containing this destination
			// and add to map with key = car, value = new set of one destination
			if (de == null) {
				HashSet<Destination> firstDe = new HashSet<Destination>();
				firstDe.add(destination);
				carAndDestination.put(taxi, firstDe);
			} else { 
			// Add the new destination to existing set.
			// Because it is a set, duplicate destinations will not
			// be added
				de.add(destination);
			}

		} catch (NumberFormatException nfe) {
			String error = "Number conversion error in " + line + " "
					+ nfe.getMessage();
			System.out.println(error);
		} catch (ArrayIndexOutOfBoundsException air) {
			String error = "Not enought items in: " + line
					+ " index position: " + air.getMessage();
			System.out.println(error);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	} // end of PROCESSLINE OF JOURNEY 2015

	/**
	 * get records from 2014 journey text file and remove "," before loaded into
	 * array list for processing
	 * 
	 * @param line
	 */
	private void processLineOfJourney1(String line) {

		try {

			Destination destination = null;
			String parts[] = line.split(",");
			String location = parts[0];
			int year = Integer.parseInt(parts[1]);
			for (Destination place : allDestination) {
				if (location.equals(place.getDestination())) {
					destination = place;
				}
			}
			allDestination2014.add(destination);

		} catch (NumberFormatException nfe) {
			String error = "Number conversion error in " + line + " "
					+ nfe.getMessage();
			System.out.println(error);
		} catch (ArrayIndexOutOfBoundsException air) {
			String error = "Not enought items in: " + line
					+ " index position: " + air.getMessage();
			System.out.println(error);
		} catch (Exception e) {
			// TODO Auto-generated catch block

			e.printStackTrace();
		}
	} // end of PROCESSLINE OF JOURNEY 2014

	/**
	 * method to print 5 most expensive and cheapest journey
	 */
	public void top5Trip() {
		this.listByFee();
		report1 = "Charges for the top 5 journeys: \n";
		for (int i = 0; i < 5; i++) {
			report1 += String.format("%-10s", allJourney2015.get(i).getCar()
					.getRegistrationNumber());
			report1 += String.format("%-30s", allJourney2015.get(i)
					.getDestination().getDestination());
			report1 += String.format("%-15s", allJourney2015.get(i)
					.getDestination().getDistance()
					+ " miles");
			report1 += String.format("%-15s", allJourney2015.get(i)
					.getPassenger() + " people");
			report1 += String.format("%-10s", " Cost  £"
					+ allJourney2015.get(i).getCost());
			report1 += "\n";

		}

		report1 += "\n\n Charges for the cheapest 5 journeys:\n\n";

		for (int i = allJourney2015.size() - 1; i > ((allJourney2015.size() - 1) - 5); i--) {
			report1 += String.format("%-10s", allJourney2015.get(i).getCar()
					.getRegistrationNumber());
			report1 += String.format("%-30s", allJourney2015.get(i)
					.getDestination().getDestination());
			report1 += String.format("%-15s", allJourney2015.get(i)
					.getDestination().getDistance()
					+ " miles");
			report1 += String.format("%-15s", allJourney2015.get(i)
					.getPassenger() + " people");
			report1 += String.format("%-10s", " Cost  £"
					+ allJourney2015.get(i).getCost());
			report1 += "\n";
		}

		this.WriteToFile("topJourneys.txt", report1);
	}

	/**method to print driver and destinations which has visited**/
	public void getDriverAndDestination() {

		Set<Map.Entry<Car, HashSet<Destination>>> entries = carAndDestination
				.entrySet();
		report2 = "Driver and Destinations : ";
		// for each entry
		// get and print the Car (the key)
		// get and print the set of Destination (the value)
		for (Map.Entry<Car, HashSet<Destination>> entry : entries) {
			// get and print driver name
			String driver = entry.getKey().getDriverName().getFullName();
			report2 += "\n" + driver + "  \n";// loop through to print out reports
			// get and print destinations
			Set<Destination> des = entry.getValue();
			Iterator<Destination> iter1 = des.iterator();
	        while (iter1.hasNext()) {
			report2 += ("   " + iter1.next().getDestination() + "\n");// loop through to report
																	
			}

		}
		this.WriteToFile("DriverAndDestination.txt", report2);
		
	}

	/**method to print destination statical**/
	public void destinationStatical() {

		HashSet<Destination> DestinationBothYear = new HashSet<Destination>();
		HashSet<Destination> Destination2014Only = new HashSet<Destination>();
		HashSet<Destination> Destination2015Only = new HashSet<Destination>();

		Iterator<Destination> iter1 = allDestination2014.iterator();
		Iterator<Destination> iter2 = allDestination2015.iterator();
		while (iter1.hasNext()) {
			Destination destination2014 = iter1.next();
			
			if (allDestination2015.contains(destination2014))
				DestinationBothYear.add(destination2014);
			else
				Destination2014Only.add(destination2014);
		}

		while (iter2.hasNext()) {
			Destination destination2015 = iter2.next();
			if (!allDestination2014.contains(destination2015))
				Destination2015Only.add(destination2015);
		}

		report3 = Destination2015Only.size() + " NEW PLACES IN 2015 :\n";
		Iterator<Destination> iter4 = Destination2015Only.iterator();
		while (iter4.hasNext()) {
			report3 += ("  " + iter4.next().getDestination() + "\n");
		}
		
		report3 += ("\n\n" + Destination2014Only.size() + " PLACES VISITED IN 2014 ONLY :\n");
		Iterator<Destination> iter5 = Destination2014Only.iterator();
		while (iter5.hasNext()) {
			report3 += ("  "+ iter5.next().getDestination() + "\n");
		}
		
		report3 += "\n\n" + DestinationBothYear.size() + " PLACES VISITED IN BOTH 2014 AND 2015 :\n";
		Iterator<Destination> iter3 = DestinationBothYear.iterator();
		while (iter3.hasNext()) {
			report3 += "  " + iter3.next().getDestination() + "\n";
		}

		
		

		this.WriteToFile("DestinationStatical.txt", report3);

	}

	public void WriteToFile(String fileName, String report) {
		FileWriter fw;
		try {
			fw = new FileWriter(fileName);
			fw.write(report);
			fw.close();
		} catch (FileNotFoundException fnf) {
			System.out.println(fileName + " not found ");
			System.exit(0);
		} catch (IOException ioe) {
			ioe.printStackTrace();
			System.exit(1);
		}
	}

}
